# -*- coding: utf-8 -*-
import aima.search as s
#Problema: Caballo de ajedrez en tablero de 2x3, comienza en (0,0) y debe recorrer todas las casillas sin repetir ninguna.
#Basicamente al estado lo definimos como una tupla  de dos elementos:
#En tupla[0] se encuentra la posicion actual del caballo codificada como tupla (f,c) entre (0,0) hasta (2,3).
#En tupla[1] se  encuentran todos los estados  tuplas que nuestro caballo a visitado.
class sonsin(s.Problem):#Redefinimos la clase problem 
    def __init__(self,  initial,  goal): #Funcion de iniciacion del problema, se encarga de crear variables que utilzaremos luego.
         self.initial, self.goal= initial,  goal #Variables que necesita utilizar el buscador base...
         self.validos= [(x, y) for x in [0, 1, 2] for y in [0, 1, 2, 3]] #Listcompression de todos los pares ordenados validos: (0,0) a (2,3).
         self.acciones= [(x,y) for x in [-2,-1,1,2] for y in [-2,-1,1,2]  if not (abs(x) == abs(y))] #Listcompression de acciones validas de caballo:(-2,-1) a (+2,+1)
    def successor(self, estado): #Definimos la funcion encargada de tomar un estado (e) y entregar la lista de sucesores: (Accion, NuevoEstado)
        res= [] 	#Creamos la lista de sucesores para el estado actual, que comienza vacia.
        for accion in self.acciones: #Probaremos por cada una de las posibles 8 acciones de un caballo
            nueva_posicion= (estado[0][0]+accion[0],  estado[0][1]+accion[1]) #Generamos el estado futuro aplicando la posible accion matematicamente.
            if (nueva_posicion in self.validos) and (nueva_posicion not in estado[1]):  #Si la nueva posicion esta entre las validas y nunca fue visitada aun:
                res.append((accion, (nueva_posicion, (estado[1]+(nueva_posicion, ))))) #Agregamos el nuevo estado a la lista de sucesores llamada res
        return res #Entregamos el conjunto de sucesores del estado actual.
    def goal_test(self,  estado): #Dado que no tenemos EO, definiremos una funcion encargada de determinar cuando lo alcanzamos.
        if (len(estado[1]) == 12): return True #Si ya visitamos todos los nodos posibles que son 12
        else: return False #Si no, seguir buscando.

if __name__ == '__main__':
    EI= ((0,0), ((0,0), ))   #Estado inicial, la Coma en EI[1] es para que concidere tupla de tupla un elemento... probar en interprete ((0,0)).
    agente= sonsin(EI,None) #Instanciamos al agente, no definimos EO por que no lo sabemos, luego definimos funcion objetivo
    path= s.breadth_first_graph_search(agente) #Pedimos que encuentre el camino a solucion segun un algoritmo de amplitud
    if path is not None: print 'Solucionado' + str([(nodo.state[0]) for nodo in path.path()[::-1]]) #Mostramos la solucion con una list compression.
    else: print 'Sin solucion' #En caso de que no encontro camino avisamos aqui.
